#include "stdafx.h"
#include "Light.h"

#include "GlobalAppData.h"

#include "Frustum.h"
#include "Renderer.h"
#include "RenderingSystem.h"

using namespace mgfx;

XMVECTOR SpotLight::InitialDirection = XMVectorSet(0, 0, 1, 0);

static const XMVECTOR InitialRight = XMVectorSet(1, 0, 0, 0);
static const XMVECTOR InitialUp = XMVectorSet(0, 1, 0, 0);


PointLightDesc::PointLightDesc()
{
	Color = XMCOLOR3F(1.0f, 0.5, 0.5f);
	Intensity = 1.0f;
	Radius = 200;
	Falloff = 1;
}


void PointLight::init( const PointLightDesc & desc )
{
	assert(desc.Radius > 0.0f);
	assert(desc.Falloff > 0.0f);

	Color = desc.Color;
	Intensity = desc.Intensity;
	Radius = desc.Radius;
	Falloff = desc.Falloff;

	Type = POINT_LIGHT;
}

PointLight* PointLight::copy() const
{
	return System->createPointLightCopy(*this);
}

SpotLightDesc::SpotLightDesc()
{
	Color = XMCOLOR3F(0.5f, 1.0, 1.0f);
	Intensity = 2.75f;
	Radius = 300;
	Falloff = 1;

	SpotAngleRad = PI / 8.0f;
	SpotFalloff = 1.0f;

	IsCastingShadows = true;
}

void SpotLight::init( const SpotLightDesc & desc )
{
	assert(desc.Radius > 0.0f);
	assert(desc.Falloff > 0.0f);
	assert(desc.SpotAngleRad > 0.0f);
	assert(desc.SpotFalloff > 0.0f);

	Color = desc.Color;
	Intensity = desc.Intensity;
	Radius = desc.Radius;
	Falloff = desc.Falloff;

	SpotAngleRad = desc.SpotAngleRad;
	SpotFalloff = desc.SpotFalloff;

	IsCastingShadows = desc.IsCastingShadows;
	ShadowMapWidth = 512;
	ShadowMapHeight = 512;

	initShadowMap();
	updateDerivedValues();

	Type = SPOT_LIGHT;
}

void SpotLight::initShadowMap()
{
	if(IsCastingShadows)
		ShadowMap = Renderer::Instance->addDepthTexture(ShadowMapWidth, ShadowMapHeight, DXGI_FORMAT_D16_UNORM);
	else
		ShadowMap = Renderer::TEXTURE_NONE;
}

void SpotLight::updateDerivedValues()
{
	SpotCosAngle = cosf(SpotAngleRad);

	XMMATRIX tmp = XMMatrixPerspectiveFovLH(2.0f * SpotAngleRad, 1.0f, Radius * 0.001f, Radius * 1.0f);
	XMStoreFloat4x4(&ProjectionMatrix, tmp);

	if(ShadowMap == Renderer::TEXTURE_NONE)
		initShadowMap();
}

void SpotLight::getViewFrustum(mmath::FrustumPersp & frustum)
{
	XMMATRIX world = XMLoadFloat4x4(&WorldTransform);
	frustum.construct(
		XMLoadFloat3(&XMFLOAT3(WorldTransform._41, WorldTransform._42, WorldTransform._43)),
		XMVector3TransformNormal(InitialDirection, world),
		XMVector3TransformNormal(InitialUp, world),
		XMVector3TransformNormal(InitialRight, world),
		2.0f * SpotAngleRad,
		1.0f,
		Radius * 0.001f,
		Radius * 1.0f
	);
}

SpotLight* SpotLight::copy() const
{
	return System->createSpotLightCopy(*this);
}
